/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.cloud.all.security.config.web;

import cn.cloud.all.security.authentication.AuthenticationProvider;
import cn.cloud.all.security.core.userdetails.UserDetailsService;
import cn.cloud.all.security.oauth2.config.annotation.SecurityBuilder;
import cn.cloud.all.security.oauth2.config.annotation.SecurityConfigurer;
import cn.cloud.all.security.web.DefaultSecurityFilterChain;

import javax.servlet.Filter;

public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends SecurityBuilder<DefaultSecurityFilterChain> {

    /**
     * Gets the {@link SecurityConfigurer} by its class name or <code>null</code> if not
     * found. Note that object hierarchies are not considered.
     *
     * @param clazz the Class of the {@link SecurityConfigurer} to attempt to get.
     */
    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(Class<C> clazz);

    /**
     * Removes the {@link SecurityConfigurer} by its class name or <code>null</code> if
     * not found. Note that object hierarchies are not considered.
     *
     * @param clazz the Class of the {@link SecurityConfigurer} to attempt to remove.
     * @return the {@link SecurityConfigurer} that was removed or null if not found
     */
    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);

    /**
     * Sets an object that is shared by multiple {@link SecurityConfigurer}.
     *
     * @param sharedType the Class to key the shared object by.
     * @param object     the Object to store
     */
    <C> void setSharedObject(Class<C> sharedType, C object);

    /**
     * Gets a shared Object. Note that object heirarchies are not considered.
     *
     * @param sharedType the type of the shared Object
     * @return the shared Object or null if it is not found
     */
    <C> C getSharedObject(Class<C> sharedType);

    /**
     * Allows adding an additional {@link AuthenticationProvider} to be used
     *
     * @param authenticationProvider the {@link AuthenticationProvider} to be added
     * @return the {@link HttpSecurity} for further customizations
     */
    H authenticationProvider(AuthenticationProvider authenticationProvider);

    /**
     * Allows adding an additional {@link UserDetailsService} to be used
     *
     * @param userDetailsService the {@link UserDetailsService} to be added
     * @return the {@link HttpSecurity} for further customizations
     */
    H userDetailsService(UserDetailsService userDetailsService) throws Exception;

    /**
     * Allows adding a {@link Filter} after one of the known {@link Filter} classes. The
     * known {@link Filter} instances are either a {@link Filter} listed in
     * {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
     * {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
     *
     * @param filter      the {@link Filter} to register after the type {@code afterFilter}
     * @param afterFilter the Class of the known {@link Filter}.
     * @return the {@link HttpSecurity} for further customizations
     */
    H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);

    /**
     * Allows adding a {@link Filter} before one of the known {@link Filter} classes. The
     * known {@link Filter} instances are either a {@link Filter} listed in
     * {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
     * {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
     *
     * @param filter       the {@link Filter} to register before the type {@code beforeFilter}
     * @param beforeFilter the Class of the known {@link Filter}.
     * @return the {@link HttpSecurity} for further customizations
     */
    H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);

    H addFilter(Filter filter);
}
